use std::{rc::Rc, cell::RefCell};

use crate::{instructions::base::{Instruction, BytecodeReader, invoke_java_method}, rtda::{Frame, DataType, Object, LocalVars}};


#[derive(Debug, Default)]
pub struct INVOKE_DYNAMIC {
    index: usize, //被调用的方法的符号引用（CONSTANT_InvokeDynamic_info常量）
    // zero1: u8,
    // zero2: u8,
}

// 以下为是hotspot jdk8源码 methodHandles.cpp line:41
// JSR 292 参考实现：方法句柄 JDK 7 参考实现将方法句柄组合表示为链。
// 链中的每个环节都有一个“vmentry”字段，该字段指向一些汇编代码，这些汇编代码在调度到链中的下一个环节之前执行一次转换。
// 当前的参考实现将几乎所有的代码生成责任都推给了（受信任的）Java 代码。方法句柄包含指向其“LambdaForm”的指针，
// 该指针包含方法句柄行为的所有详细信息。LambdaForm 是一个普通的 Java 对象，由用 Java 编码的运行时管理。

// 此方法实现未按照hotspot实现（看不懂源码，未找到如何实现），只针对特定方式实现，不具备任何参考价值。
// 实现方式为 常量InvokeDynamic存储的信息：methodhandle（指向LambdaMetafactory.metafactory()方法），
// 组装参数调用 methodhandle.invokeExact() 得到callsite（即执行LambdaMetafactory.metafactory()方法）。
// 得到callSite后。通过执行callSite.dynamicInvoker()得到要执行方法的 methodhandle（参考MethodHandleNatives.java line:313）
// 直接返回了内部的argL0字段，此值为要执行方法的匿名类。在使用::双冒号时此字段不是匿名类，因此现不支持::。

impl Instruction for INVOKE_DYNAMIC {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.index = reader.read_u16() as usize;
        reader.read_u8(); // must be 0
        reader.read_u8(); // must be 0
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let current_class = frame.borrow().get_method().get_class();
        let cp = current_class.get_constant_pool().unwrap();
        let cp_invoke_dynamic = cp.get_constant(self.index).expect("constant is none").invoke_dynamic();
        let call_site = cp_invoke_dynamic.lock().unwrap().resolved(frame.clone());
        assert!(call_site.is_some());
        let j_thread = frame.borrow().get_thread().lock().unwrap().get_j_thread();
        // 取出callsite中的methodhandle
        let mh = dynamic_invoker(call_site.unwrap(), j_thread);
        unsafe {
            let bmh = &*mh.unwrap();
            // BoundMethodHandle$xxxxxx@xxx[type, form, _, _ , argL0(匿名类或?)]
            if let DataType::Slots(bmh_slots) = bmh.get_data() {

                let obj = bmh_slots.get_ref(4);
                
                let stack = frame.borrow().get_operand_stack();
    
                if let Some(o) = obj {
                    let class_name = { &*o }.get_class().get_name();
                    // MemberName [class, methodName, methodType, flags, resolution]
                    if "java/lang/invoke/MemberName" == class_name {
                        // 经测试，使用线程外定义的对象会返回DirectMethodHandle 取到的obj为MemberName无法直接使用
                        // 后续可尝试执行此MemberName， 执行所需参数从stack中获取。
                        panic!("暂不支持");
                    } else {
                        stack.borrow_mut().push_ref(Some(o));
                    }
                } else {
                    stack.borrow_mut().push_ref(None);
                }
                // println!("{}", stack.borrow());
                return;
            }
        }
        panic!("暂不支持");
    }
}


// dynamicInvoker
fn dynamic_invoker(callsite: *mut Object, jvm_rust: Option<*mut Object>) -> Option<*mut Object> {
    let callsite_class = unsafe { &*callsite }.get_class();
    let dynamic_nvoker_method = callsite_class.get_instance_method("dynamicInvoker", "()Ljava/lang/invoke/MethodHandle;").unwrap();

    let mut vars = LocalVars::new_local_vars(dynamic_nvoker_method.get_max_locals());
    // self
    vars.set_ref(0, Some(callsite));

    let stack = invoke_java_method(dynamic_nvoker_method, vars, None, jvm_rust);

    let mh_obj = stack.borrow_mut().pop_ref();
    mh_obj
}